/**
 ****************************************************
 *   Ftp.java
 *   功能    
 *   历史    2006-11-4             zhuliren
 ****************************************************
 */
package jude.java.money.net.ftp;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;

/**不稳定*/
public class Ftp extends AFtp {

	private FTPClient ftp;

	/**
	 * @param ip
	 *            String 机器IP
	 * @param port
	 *            String 机器FTP端口号
	 * @param username
	 *            String FTP用户名
	 * @param password
	 *            String FTP密码
	 * @throws Exception
	 */
	public Ftp(String ip, int port, String username, String password) {
		super(ip, port, username, password);
		this.ftp = new FTPClient();
	}

	/**
	 * @see Ftp#Ftp(String, int, String, String)
	 */
	public Ftp(String ip, String username, String password) {
		this(ip, 21, username, password);
	}

	public boolean isConnected() {
		return ftp != null && ftp.isConnected();
	}

	/**
	 * 登录FTP
	 */
	public boolean login() {
		try {
			ftp.connect(this.host, this.port);
			boolean b = ftp.login(userName, password);
			if (!b)
				System.out.println("login fail");
			return b;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 退出FTP
	 */
	public boolean logout() {
		// 用ftp.closeServer()断开FTP出错时用下更语句退出
		try {
			ftp.logout();
			ftp.disconnect(); // 取得服务器的返回信息
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	public void buildPath(String path) {
		path = normalizeRemotePath(path);
		StringTokenizer s = new StringTokenizer(path, "/"); // sign
		String pathName = "";
		boolean mkdir = false;
		while (s.hasMoreElements()) {
			String dir = ((String) s.nextElement()).trim();
			if ("".equals(dir))
				continue;
			pathName = pathName + "/" + (String) dir;
			try {
				mkdir |= ftp.makeDirectory(pathName + "\r\n");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		if (mkdir) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
			}
		}
	}
	
	@Override
	public List<FtpFile> listFiles(String path) {
		ArrayList<FtpFile> result = new ArrayList<FtpFile>();
		try {
			if (path != null) {
				path = normalizeRemotePath(path);
				ftp.changeWorkingDirectory(path);
			}
			System.out.println(ftp.pwd());
			System.out.println(ftp.getReplyString());
			cd("/");
			FTPFile[] files = ftp.listFiles();
			for (int i = 0; i < files.length; i++) {
				FTPFile file = files[i];
				String name = file.getName();
				if (name.charAt(0) != '.')
					result.add(new FtpFile(name, file.isDirectory()));
			}
		} catch (Throwable e) {
			e.printStackTrace();
		}
		return result;
	}
	
	/** 本地目录下的所有内容上传到远程目录下 */
	public boolean uploadDirectory(File file, String remote) throws IOException {
		if (!file.isDirectory()) {
			return uploadFile(file, remote);
		}
		String path = file.getPath();
		if (!path.endsWith(File.separator))
			path += File.separator;
		if (!remote.endsWith("/"))
			remote += "/";
		String[] files = file.list();
		for (String f : files) {
			File sub = new File(path + f);
			String _remote = remote + f;
			boolean r = false;
			if (sub.isDirectory())
				r = uploadDirectory(sub, _remote);
			else
				r = uploadFile(sub, _remote);
			if (!r)
				return false;
		}
		return true;
	}

	/**
	 * 从流中上传文件
	 * 
	 * @param in
	 *            输入流, 将被关闭
	 * @param remote
	 *            远程路径
	 * @throws IOException
	 */
	public boolean uploadFile(InputStream in, String remote) throws IOException {
		String path[] = split(remote);
		if (!ftp.changeWorkingDirectory(path[0])) {
			buildPath(path[0]);
			ftp.changeWorkingDirectory(path[0]);
		}
		ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
		boolean success = ftp.storeFile(path[1], in);
		in.close();
		return success;
	}

	@Override
	public boolean uploadFile(String local, String remote) throws IOException {
		return uploadFile(new FileInputStream(local), remote);
	}

	public boolean downFile(String remote, String file) throws IOException {
		FileOutputStream out = new FileOutputStream(file);
		downFile(remote, out);
		out.close();
		return true;
	}

	public void downFile(String remote, OutputStream out) throws IOException {
		String path[] = split(remote);
		ftp.changeWorkingDirectory(path[0]);
		ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
		if (!ftp.retrieveFile(path[1], out)) {
			throw new RuntimeException("fail to download file: " + remote);
		}
		// System.out.print(ftp.printWorkingDirectory());
	}

	public boolean downDirectory(String remote, String file) throws IOException {
		throw new RuntimeException("Unsuport down load whole dir");
	}

	public boolean deleteFile(String remote) throws IOException {
		String path[] = split(remote);
		ftp.changeWorkingDirectory(path[0]);
		ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
		return ftp.deleteFile(path[1]);
	}

	/** 空文件夹 */
	public boolean deleteDirectory(String remote) throws IOException {
		return ftp.removeDirectory(remote);
	}

	public boolean exists(String remote) {
		String path[] = split(remote);
		try {
			if (!ftp.changeWorkingDirectory(path[0])) {
				return false;
			}
			String[] names = ftp.listNames();
			if (names == null || names.length == 0)
				return false;
			for (String name : names) {
				if (path[1].equals(name))
					return true;
			}
		} catch (Exception e) {
			return false;
		}
		return false;
	}

	@Override
	public boolean cd(String path) {
		try {
			return ftp.changeWorkingDirectory(path);
		} catch (IOException e) {
			return false;
		}
	}

	@Override
	public void cmd(String cmd) {
		try {
			ftp.sendCommand(cmd);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void test() {
		try {
			ftp.listNames();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}